home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / comm / tcp / AmigaTCP.lha / AmigaTCP / src / ax25.c < prev    next >
C/C++ Source or Header  |  1989-06-24  |  13KB  |  614 lines

  1. /* Vestigial AX.25 link layer, understands only UI frames */
  2.  
  3. #include <stdio.h>
  4. #include "machdep.h"
  5. #include "mbuf.h"
  6. #include "iface.h"
  7. #include "timer.h"
  8. #include "arp.h"
  9. #include "slip.h"
  10. #include "ax25.h"
  11. #include <ctype.h>
  12.  
  13. #ifdef    TRACE
  14. #include "trace.h"
  15. #endif
  16.  
  17. /* AX.25 broadcast address: "QST-0" in shifted ascii */
  18. struct ax25_addr ax25_bdcst = {
  19.     'Q'<<1, 'S'<<1, 'T'<<1, ' '<<1, ' '<<1, ' '<<1,
  20.     ('0'<<1) | E,
  21. };
  22. struct ax25_addr mycall;
  23. int digipeat;        /* Controls digipeating */
  24.  
  25. /* Send IP datagrams in AX.25 UI frames using ARP */
  26. int
  27. ax_send(bp,interface,gateway,precedence,delay,throughput,reliability)
  28. struct mbuf *bp;
  29. struct interface *interface;
  30. int32 gateway;
  31. char precedence;
  32. char delay;
  33. char throughput;
  34. char reliability;
  35. {
  36.     char *hw_addr,*res_arp();
  37.  
  38.     hw_addr = res_arp(interface,ARP_AX25,gateway,bp);
  39.     if(hw_addr != NULLCHAR)
  40.         (*interface->output)(interface,(struct ax25_addr *)hw_addr,
  41.             interface->hwaddr,PID_IP,bp);
  42. }
  43. /* Send a raw packet to the KISS TNC using AX.25 link header.
  44.  * Note that the calling order here must match ec_output
  45.  * since ARP also uses it.
  46.  */
  47. kiss_output(interface,dest,src,pid,bp)
  48. struct interface *interface;
  49. struct ax25_addr *dest;    /* Destination AX.25 address (7 bytes, shifted) */
  50. struct ax25_addr *src;    /* Source AX.25 address (7 bytes, shifted) */
  51. char pid;        /* Protocol ID */
  52. struct mbuf *bp;    /* Data field (follows PID) */
  53. {
  54.     register struct mbuf *hbp;
  55.     struct mbuf *ax_encode();
  56.     struct slip *sp;
  57.  
  58.     if((bp = ax_encode(dest,src,pid,bp)) == NULLBUF)
  59.         return;
  60. #ifdef    TRACE
  61.     if(trace & TRACE_AX25){
  62.         printf("%s sent:\r\n",interface->name);
  63.         if((trace & TRACE_HDR) > 1)
  64.             ax25_dump(bp);
  65.         if(trace & TRACE_DUMP)
  66.             hexdump(bp);
  67.         if(trace & TRACE_ASCII)
  68.             asciidump(bp);
  69.         fflush(stdout);
  70.     }
  71. #endif
  72.     /* Put type field for KISS TNC on front */
  73.     if((hbp = alloc_mbuf(1)) == NULLBUF){
  74.         free_p(bp);
  75.         return;
  76.     }
  77.     *hbp->data = 0;
  78.     hbp->cnt = 1;
  79.     hbp->next = bp;
  80.     slipq(interface->dev,hbp);
  81. }
  82.  
  83. /* Put a AX.25 header on the front of a packet */
  84. struct mbuf *
  85. ax_encode(dest,src,pid,bp)
  86. struct ax25_addr *dest;    /* Destination AX.25 address (7 bytes, shifted) */
  87. struct ax25_addr *src;    /* Source AX.25 address (7 bytes, shifted) */
  88. char pid;        /* Protocol ID */
  89. struct mbuf *bp;    /* Data field (follows PID) */
  90. {
  91.     register struct ax25_addr *ap;
  92.     struct mbuf *abp;
  93.     char *cp;
  94.     int ndigi;
  95.     int16 hdr_len;
  96.  
  97.     /* Determine length of dest addr */
  98.     for(ndigi = 0,ap = dest; (ap->ssid & E) == 0;
  99.             ap = (struct ax25_addr *) ((char *)ap + AXALEN))
  100.         ndigi++;
  101.  
  102.     /* Compute header length:
  103.      * 2 AX.25 address fields for source and dest +
  104.      * "ndigi" AX.25 address field(s) for digipeaters +
  105.      * 2 bytes for control and PID fields
  106.      */
  107.  
  108.     hdr_len = (2 + ndigi)*AXALEN + 2;
  109.  
  110.     /* Create AX.25 link level header */
  111.     if((abp = alloc_mbuf(hdr_len)) == NULLBUF){
  112.         free_p(bp);
  113.         return NULLBUF;
  114.     }
  115.     abp->cnt = hdr_len;
  116.  
  117.     /* Now fill it in */
  118.  
  119.     ap = (struct ax25_addr *)(abp->data);
  120.  
  121.     bcopy((char *)dest,(char *)ap,AXALEN);
  122.     ap->ssid &= ~E;
  123.     ap = (struct ax25_addr *) ((char *)ap + AXALEN);
  124.     dest = (struct ax25_addr *) ((char *)dest + AXALEN);
  125.  
  126.     bcopy((char *)src,(char *)ap,AXALEN);
  127.     ap->ssid &= ~E;
  128.     cp = (char *)ap;    /* get pointer to last address (source) */
  129.     ap = (struct ax25_addr *) ((char *)ap + AXALEN);
  130.  
  131.     while(ndigi-- != 0) {
  132.         bcopy((char *)dest,(char *)ap,AXALEN);
  133.         dest = (struct ax25_addr *) ((char *)dest + AXALEN);
  134.         cp = (char *)ap;
  135.         ap = (struct ax25_addr *) ((char *)ap + AXALEN);
  136.     }
  137.     ((struct ax25_addr *)cp)->ssid |= E;    /* Mark end of address field */    
  138.  
  139.     cp = (char *)ap;    /* Point to first byte past address field */
  140.     *cp++ = UI;
  141.     *cp++ = pid;
  142.  
  143.     abp->next = bp;        /* Link in data field */
  144.     return abp;
  145. }
  146. /* Process incoming KISS TNC frame */
  147. kiss_recv(interface,bp)
  148. struct interface *interface;
  149. struct mbuf *bp;
  150. {
  151.     pullup(&bp,NULLCHAR,1);    /* remove KISS TNC type field */
  152.     if(bp != NULLBUF)
  153.         ax_recv(interface,bp);
  154. }
  155. /* Process incoming AX.25 packets.
  156.  * After optional tracing, the address field is examined. If it is
  157.  * directed to us as a digipeater, repeat it.  If it is addressed to
  158.  * us or to QST-0, kick it upstairs depending on the protocol ID.
  159.  */
  160. int
  161. ax_recv(interface,bp)
  162. struct interface *interface;
  163. struct mbuf *bp;
  164. {
  165.     void arp_input(),ip_route();
  166.     struct ax25_addr *ap,*ap1;
  167.     char pid,multicast,ours,*control,*cbyte();
  168.     int addrsize;
  169.     struct mbuf *hbp;
  170.  
  171. #ifdef    TRACE
  172.     if(trace & TRACE_AX25){
  173.         printf("%s recv:\r\n",interface->name);
  174.         if((trace & TRACE_HDR) > 1)
  175.             ax25_dump(bp);
  176.         if(trace & TRACE_DUMP)
  177.             hexdump(bp);
  178.         if(trace & TRACE_ASCII)
  179.             asciidump(bp);
  180.         fflush(stdout);
  181.     }
  182. #endif
  183.     control = cbyte(bp);        /* control -> control byte */
  184.  
  185.     ap = (struct ax25_addr *)bp->data;    /* -> address field */
  186.     addrsize = control - (char *)ap;    /* # bytes in address field */
  187.     /* Check for either a missing control byte or a residual length
  188.      * address field
  189.      */
  190.     if(control == NULL || addrsize % AXALEN != 0){
  191.         free_p(bp);
  192.         return;
  193.     }
  194.     addrsize /= AXALEN; /* # addresses in address field */
  195.     /* Check for invalid address field (too short or odd length) */    
  196.     if(addrsize < 2) {
  197.         free_p(bp);
  198.         return;
  199.     }
  200.     /* Rescan, looking for our call in the repeater fields, if any.
  201.      * Repeat appropriate packets.
  202.      */
  203.     /* for(ap1 = &ap[2]; ap1 < &ap[addrsize]; ap1++){ */
  204.  
  205.     for(ap1 = (struct ax25_addr *) ((char *)ap + 2*AXALEN);
  206.         ap1 < (struct ax25_addr *) ((char *)ap + addrsize*AXALEN);
  207.         ap1 = (struct ax25_addr *) ((char *)ap1 + AXALEN)) {
  208.  
  209.         if((ap1->ssid & REPEATED) == 0){
  210.             /* Check if packet is directed to us as a digipeater */
  211.             if(digipeat && addreq(ap1,&mycall)){
  212.                 /* Yes, kick it back out */
  213.                 ap1->ssid |= REPEATED;
  214.                 /* Put type field for KISS TNC on front */
  215.                 if((hbp = alloc_mbuf(1)) == NULLBUF){
  216.                     free_p(bp);
  217.                     return;
  218.                 }
  219.                 *hbp->data = 0;
  220.                 hbp->cnt = 1;
  221.                 hbp->next = bp;
  222.                 slipq(interface->dev,hbp);
  223.             } else {
  224.                 /* Addressed to some other digipeater */
  225.                 free_p(bp);
  226.             }
  227.             return;
  228.         }
  229.     }
  230.     /* Packet has passed all repeaters, now look at destination */
  231.     ours = 0;
  232.     if(addreq(&ap[0],&ax25_bdcst)){
  233.         multicast = 1;    /* Broadcast packet */
  234.     } else if(addreq(&ap[0],&mycall)){
  235.         multicast = 0;    /* Packet directed at us */
  236.         ours = 1;
  237. #if    0
  238.     /* we really do want to see all of the packets, later on */
  239.     } else {
  240.         /* Not for us */
  241.         free_p(bp);
  242.         return;
  243. #endif
  244.     }
  245.     /* Now remove the header and the control field. Note: This will
  246.      * have to be changed if the connected mode of AX.25 (ugh!) is ever
  247.      * implemented
  248.      */
  249.     pullup(&bp,NULLCHAR,1 + addrsize * AXALEN);
  250.  
  251.     /* Examine the protocol ID field and switch to the right protocol */
  252.     if(pullup(&bp,&pid,1) != 1)
  253.         return;    /* No PID, probably not an I-frame */
  254.     switch(pid & 0xff){
  255.     case PID_ARP:
  256.         arp_input(interface,bp);
  257.         break;
  258.     case PID_IP:
  259.         if (!(ours || multicast)) {
  260.             free_p(bp);
  261.             break;
  262.         }
  263.         ip_route(bp,multicast);
  264.         break;
  265. #ifdef    NETROM
  266.     case PID_NETROM:
  267.         netrom_input(interface, bp);
  268.         break;
  269. #endif
  270.     default:
  271.         free_p(bp);
  272.         break;
  273.     }
  274. }
  275. /* Display or change our AX.25 address */
  276. domycall(argc,argv)
  277. int argc;
  278. char *argv[];
  279. {
  280.     char buf[15];
  281.  
  282.     if(argc < 2){
  283.         pax25(buf,&mycall);
  284.         printf("%s\r\n",buf);
  285.         return 0;
  286.     }
  287.     if(setcall(&mycall,argv[1]) == -1)
  288.         return -1;
  289.     mycall.ssid |= E;
  290. }
  291. /*
  292.  * setcall - convert callsign plus substation ID of the form
  293.  * "KA9Q-0" to AX.25 (shifted) address format
  294.  *   Address extension bit is left clear
  295.  *   Return -1 on error, 0 if OK
  296.  */
  297. int
  298. setcall(out,call)
  299. struct ax25_addr *out;
  300. char *call;
  301. {
  302.     int csize;
  303.     unsigned ssid;
  304.     register int i;
  305.     register char *cp,*dp;
  306.     char c,*index();
  307.  
  308.     if(out == (struct ax25_addr *)NULL || call == NULLCHAR || *call == '\0'){
  309.         return -1;
  310.     }
  311.     /* Find dash, if any, separating callsign from ssid
  312.      * Then compute length of callsign field and make sure
  313.      * it isn't excessive
  314.      */
  315.     dp = index(call,'-');
  316.     if(dp == NULLCHAR)
  317.         csize = strlen(call);
  318.     else
  319.         csize = dp - call;
  320.     if(csize > 6)
  321.         return -1;
  322.     /* Now find and convert ssid, if any */
  323.     if(dp != NULLCHAR){
  324.         dp++;    /* skip dash */
  325.         ssid = atoi(dp);
  326.         if(ssid > 15)
  327.             return -1;
  328.     } else
  329.         ssid = 0;
  330.     /* Copy upper-case callsign, left shifted one bit */
  331.     cp = out->call;
  332.     for(i=0;i<csize;i++){
  333.         c = *call++;
  334.         if(islower(c))
  335.             c = toupper(c);
  336.         *cp++ = c << 1;
  337.     }
  338.     /* Pad with shifted spaces if necessary */
  339.     for(;i<6;i++)
  340.         *cp++ = ' ' << 1;
  341.     
  342.     /* Insert substation ID field and set reserved bits */
  343.     out->ssid = 0x60 | (ssid << 1);
  344.     return 0;
  345. }
  346. static
  347. addreq(a,b)
  348. register struct ax25_addr *a,*b;
  349. {
  350.     if(bcmp(a->call,b->call,ALEN) != 0)
  351.         return 0;
  352.     if((a->ssid & SSID) != (b->ssid & SSID))
  353.         return 0;
  354.     return 1;
  355. }
  356. /* Convert encoded AX.25 address to printable string */
  357. pax25(e,addr)
  358. char *e;
  359. struct ax25_addr *addr;
  360. {
  361.     register int i;
  362.     char c,*cp;
  363.  
  364.     cp = addr->call;
  365.     for(i=6;i != 0;i--){
  366.         c = (*cp++ >> 1) & 0x7f;
  367.         if(c == ' ')
  368.             break;
  369.         *e++ = c;
  370.     }
  371.     sprintf(e,"-%d",(addr->ssid >> 1) & 0xf);    /* ssid */
  372. }
  373. /* Print a string of AX.25 addresses in the form
  374.  * "KA9Q-0 [via N4HY-0,N2DSY-2]"
  375.  */
  376. psax25(e,addr)
  377. register char *e;
  378. register struct ax25_addr *addr;
  379. {
  380.     int i;
  381.  
  382.     for(i=0;;i++){
  383.         pax25(e,addr);
  384.         if(addr->ssid & E)
  385.             break;
  386.         if(i == 0)
  387.             strcat(e," via ");
  388.         else
  389.             strcat(e,",");
  390.         e += strlen(e);
  391.         /* addr++; */
  392.         addr = (struct ax25_addr *) ((char *)addr + AXALEN);
  393.     }
  394. }
  395. /* Return a pointer to the control byte in the given frame */
  396. char *
  397. cbyte(fp)
  398. register struct mbuf *fp;
  399. {
  400.     register char *cp;
  401.     register unsigned cnt;
  402.  
  403.     if(fp == NULLBUF || fp->data == NULLCHAR)
  404.         return NULLCHAR;
  405.  
  406.     cnt = fp->cnt;
  407.     cp = fp->data;
  408.     while(cnt != 0 && (*cp & E) == 0){
  409.         cnt--;
  410.         cp++;
  411.     }
  412.     /* If the address field never ended, cnt = 0; if it ended
  413.      * on the last byte of a frame, cnt = 1. In either case,
  414.      * there is no control field
  415.      */
  416.     if(cnt <= 1)
  417.         return NULLCHAR;
  418.     else
  419.         return cp + 1;
  420. }
  421. dokiss(argc,argv)
  422. int argc;
  423. char *argv[];
  424. {
  425.     struct interface *ifp;
  426.     struct mbuf *hbp;
  427.     int i;
  428.     char *cp;
  429.  
  430.     if(argc < 2){
  431.         printf("Interface name missing\r\n");
  432.         return 1;
  433.     }
  434.     for(ifp=ifaces;ifp != NULLIF;ifp = ifp->next){
  435.         if(strcmp(argv[1],ifp->name) == 0)
  436.             break;
  437.     }
  438.     if(ifp == NULL){
  439.         printf("Interface \"%s\" unknown\r\n",argv[1]);
  440.         return 1;
  441.     }
  442.     if(ifp->output != kiss_output){
  443.         printf("Interface \"%s\" not kiss\r\n",argv[1]);
  444.         return 1;
  445.     }
  446.     if(argc < 3){
  447.         printf("Data field missing\r\n");
  448.         return 1;
  449.     }
  450.     /* Number of bytes in message == number of args - 2, since
  451.      * first two args are "kiss" and the interface name
  452.      */
  453.     if((hbp = alloc_mbuf(argc - 2)) == NULLBUF){
  454.         free_p(hbp);
  455.         return;
  456.     }
  457.     hbp->cnt = argc - 2;
  458.     hbp->next = NULL;
  459.     for(i=2,cp = hbp->data;i < argc;i++,cp++){
  460.         *cp = htoi(argv[i]);
  461.     }
  462.     slipq(ifp->dev,hbp);
  463. }
  464. #ifdef    TRACE
  465.  
  466. /* Dump an AX.25 packet header */
  467. ax25_dump(abp)
  468. struct mbuf *abp;
  469. {
  470.     struct mbuf *bp;
  471.     struct ax25_addr src,dest,addr;
  472.     char tmp[20],*cp,control,cmdrsp,pid;
  473.     int16 len,type,ftype();
  474.  
  475.     dup_p(&bp,abp,0,len_mbuf(abp));
  476.  
  477.     /* Read and print the destination and source addresses */
  478.     if(pullup(&bp,(char *)&dest,AXALEN) != AXALEN)
  479.         goto quit;
  480.     if(pullup(&bp,(char *)&src,AXALEN) != AXALEN)
  481.         goto quit;
  482.  
  483.     pax25(tmp,&src);
  484.     printf("AX25: %s",tmp);
  485.     pax25(tmp,&dest);
  486.     printf("->%s",tmp);
  487.  
  488.     if((src.ssid & E) == 0){
  489.         /* Find the last address entry in the digi string */
  490.         printf(" v");
  491.         while(pullup(&bp,(char *)&addr,AXALEN) == AXALEN){
  492.             pax25(tmp,&addr);
  493. #ifdef    AMIGA
  494.             /* this is just personal preference; reminds me of 
  495.                the WA8DED TNC-1 code */
  496.             printf(" %s%s",tmp,(addr.ssid & REPEATED) ? "*":"");
  497. #else
  498.             printf(" %s%s",tmp,(addr.ssid & REPEATED) ? "H":"");
  499. #endif
  500.             if(addr.ssid & E)
  501.                 break;    /* Found it */
  502.         }
  503.     }
  504.     if(pullup(&bp,&control,1) != 1)
  505.         goto quit;
  506.  
  507.     putchar(' ');
  508.     type = ftype(control);
  509.     switch(type){
  510.     case I:
  511.         printf("I");
  512.         break;
  513.     case SABM:
  514.         printf("SABM");
  515.         break;
  516.     case DISC:
  517.         printf("DISC");
  518.         break;
  519.     case DM:
  520.         printf("DM");
  521.         break;
  522.     case UA:
  523.         printf("UA");
  524.         break;
  525.     case RR:
  526.         printf("RR");
  527.         break;
  528.     case RNR:
  529.         printf("RNR");
  530.         break;
  531.     case REJ:
  532.         printf("REJ");
  533.         break;
  534.     case FRMR:
  535.         printf("FRMR");
  536.         break;
  537.     case UI:
  538.         printf("UI");
  539.         break;
  540.     default:
  541.         printf("[invalid]");
  542.     }
  543.  
  544.     if((dest.ssid & C) != (src.ssid & C)){
  545.         if(dest.ssid & C)
  546.             cmdrsp = COMMAND;
  547.         else
  548.             cmdrsp = RESPONSE;
  549.     } else 
  550.         cmdrsp = UNKNOWN;
  551.     /* Dump poll/final bit */
  552.     if(control & PF){
  553.         switch(cmdrsp){
  554.         case COMMAND:
  555.             printf("(P)");
  556.             break;
  557.         case RESPONSE:
  558.             printf("(F)");
  559.             break;
  560.         default:
  561.             printf("(P/F)");
  562.             break;
  563.         }
  564.     }
  565.     /* Dump sequence numbers */
  566.     if((type & 0x3) != U)    /* I or S frame? */
  567.         printf(" NR=%d",(control>>5)&7);
  568.     if((type & 0x1) == I)    /* I frame? */
  569.         printf(" NS=%d",(control>>1)&7);
  570.  
  571.     if(pullup(&bp,&pid,1) != 1)
  572.         goto quit;
  573.     printf(" pid 0x%x\r\n",pid & 0xff);
  574.     if((trace & TRACE_HDR) > 2){
  575.         switch(pid & 0xff){
  576.         case PID_ARP:
  577.             arp_dump(bp);
  578.             break;
  579.         case PID_IP:
  580.             ip_dump(bp);
  581.             break;
  582. #ifdef    NETROM
  583.         case PID_NETROM:
  584.             netrom_dump(bp);
  585.             break;
  586. #endif
  587.         }
  588.     }
  589.     free_p(bp);
  590.     fflush(stdout);
  591.     return;
  592. quit:    /* I hate go-to's, but sometimes there's no real choice */
  593.     free_p(bp);
  594.     printf("\r\n");
  595.     fflush(stdout);
  596. }
  597. /* Figure out the frame type from the control field
  598.  * This is done by masking out any sequence numbers and the
  599.  * poll/final bit after determining the general class (I/S/U) of the frame
  600.  */
  601. static
  602. int16
  603. ftype(control)
  604. register char control;
  605. {
  606.     if((control & 1) == 0)    /* An I-frame is an I-frame... */
  607.         return I;
  608.     if(control & 2)            /* U-frames use all except P/F bit for type */
  609.         return(control & ~PF);
  610.     else                    /* S-frames use low order 4 bits for type */
  611.         return(control & 0xf);
  612. }
  613. #endif
  614.